"""
面向对象编程的三大特性是封装、继承和多态。
封装是面向对象编程的一个重要特性，它通过控制对类成员（属性和方法）的访问来保护数据。
封装将数据（属性）和操作数据的方法（行为）绑定在一起，并隐藏对象的内部实现细节，只暴露必要的接口给外部使用。
我们通过封装来控制对类成员的访问，以保护数据的安全性和完整性，达到提高代码的可维护性和灵活性的目的。

Python通过命名约定实现了私有成员和公有成员的概念。
公有成员（public member）是在类的内部和外部都可以访问的属性和方法。
在Python中，默认情况下所有的属性和方法都是公有的。
- name 和 age 是公有属性，可以在类的外部通过对象直接访问。
- speak 是公有方法，可以在类的外部通过对象直接调用。
"""
class Animal:
    def __init__(self, name, age):
        self.name = name  # 公有属性
        self.age = age    # 公有属性

    def speak(self):
        return f"{self.name} makes a sound."

# 创建对象
animal = Animal("Buddy", 5)
# 访问公有属性
print(animal.name)      # 输出：Buddy
print(animal.age)       # 输出：5
# 调用公有方法
print(animal.speak())   # 输出：Buddy makes a sound.
#私有成员（private member）是只能在类的内部访问的属性和方法。
#Python通过在属性或方法名前加双下划线（__）来定义私有成员。
class Animal:
    def __init__(self, name, age):
        self.__name = name  # 私有属性
        self.__age = age  # 私有属性

    def __get_info(self):  # 私有方法
        return f"{self.__name} is {self.__age} years old."

    def get_name(self):  # 公有方法
        return self.__name

    def get_age(self):  # 公有方法
        return self.__age

    def set_age(self, age):  # 公有方法
        if age > 0:
            self.__age = age
        else:
            print("Age must be positive")
        print(self.__get_info())


# 创建对象
animal = Animal("Buddy", 5)
# 尝试访问私有属性
# print(animal.__name)          # 会报错：AttributeError: 'Animal' object has no attribute '__name'
# print(animal.__age)           # 会报错：AttributeError: 'Animal' object has no attribute '__age'

# 使用公有方法访问私有属性
print(animal.get_name(), animal.get_age())  # 输出：Buddy, 5

# 修改私有属性
animal.set_age(6)
# 再次使用公有方法访问私有属性
print(animal.get_name(), animal.get_age())  # 输出：Buddy, 6
# print(animal.__get_info())    # 会报错：AttributeError: 'Animal' object has no attribute '__get_info'
# 在这个例子中，私有属性__name和__age和私有方法__get_info()就被封装在类中。
# 而公有方法get_name()、get_age()和set_age()在外部提供了接口，用来访问（或修改）类内的私有属性和调用类内的私有方法。
# 实际上，Python并没有真正的私有属性和方法，它是通过名称重整（name mangling）来模拟私有成员。
# 名称重整是在成员名字前加上_类名前缀，从而修改其名称使得外部访问变得困难。
# 在类的外部，可以通过 _类名__私有属性名 的方式强行访问私有属性。
# 但这种方式不推荐使用，因为它破坏了封装性。
class Animal:
    def __init__(self, name):
        self.__name = name  # 私有属性

# 创建对象
animal = Animal("Buddy")
# 强行访问重整后的私有属性
print(animal._Animal__name)  # 输出：Buddy
"""
继承是面向对象编程的核心概念之一，它允许一个类（子类）继承另一个类（父类）的属性和方法，从而实现代码重用和层次化结构。
多态是面向对象编程的另一个重要特性，允许不同类的对象通过同一个接口调用不同的实现。
一种常见的父类和子类的关系是包含关系。
譬如猫和狗都属于动物，那么我们可以设计动物类为父类，设计猫类和狗类为两个子类。
- 继承的语法
  - 在定义子类时，使用括号将父类名放在子类名后面，表示该子类继承自父类。例如：class Dog(Animal):。

- super()函数
  - super()函数用于调用父类的方法，特别是在子类中重写了父类的方法时。
  - 例如，在子类的构造方法中调用父类的构造方法：super().__init__(name, age)。

- 方法重写
  - 子类可以重写父类的方法，即在子类中定义与父类同名的方法，从而实现不同的功能。
  - 在Dog和Cat类中，重写了Animal类的speak()方法和info()方法。这属于多态的体现。

- 子类访问父类的属性和方法
  - 子类可以直接访问父类的公有属性和方法。
  - 子类可以通过super()来调用父类版本的方法。
"""
# 定义父类
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self):
        pass

    def info(self):
        return f"{self.name} is {self.age} years old."
# 定义子类
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)     # 调用父类的构造方法
        self.breed = breed

    def speak(self):                    # 重写父类的speak()方法
        return f"{self.name} says Woof!"

    def info(self):
        parent_info = super().info()    # 调用父类的info()方法
        return f"{parent_info} And is a {self.breed}."

class Cat(Animal):
    def __init__(self, name, age, color):
        super().__init__(name, age)     # 调用父类的构造方法
        self.color = color

    def speak(self):                    # 重写父类的speak()方法
        return f"{self.name} says Meow!"

    def info(self):
        parent_info = super().info()    # 调用父类的info()方法
        return f"{parent_info} And is {self.color} in color."
# 创建子类对象
dog = Dog("Buddy", 5, "Teddy")
cat = Cat("Lucky", 3, "black")

# 调用方法
print(dog.speak())  # 输出：Buddy says Woof!
print(cat.speak())  # 输出：Lucky says Meow!
print(dog.info())   # 输出：Buddy is 5 years old. and is a Teddy.
print(cat.info())   # 输出：Lucky is 3 years old. and is black in color.
# Python支持多继承，即一个类可以继承多个父类。多继承的语法如下：
class Parent1:
    pass

class Parent2:
    pass

class Child(Parent1, Parent2):
    pass